import { Server } from 'socket.io'
import Game_Interface from '../../common_models/Game_Interface';
import Judge from './Judge';
import Vote from './Vote';
import Player from './Player';

const moment = require('moment');

// 游戏类
export default class Game implements Game_Interface {
    io: Server
    playerArr: Player[]
    voteArr: Vote[]
    judge: Judge
    gameNumber: number
    playerLimit: number
    gameState: string

    constructor(io: Server) {
        this.io = io
        this.playerArr = [];        // 存Player类的实例，法官不在这个数组中
        this.voteArr = [];          // 投票数组，存Vote类的实例
        this.judge = null;          // Judge类的实例
        this.gameNumber = moment().utc(true).format('YYYYMMDDHHmmss');
        this.playerLimit = 12;
        this.gameState = '等待开始';

        // 实例化Game类时，开始执行socket监听
        this.socketHandler()
    }

    // socket事务处理
    socketHandler() {
        // 当用户连接
        this.io.on('connection', (socket) => {
            // 当前这个连接的玩家对象。这个对象在game.playerArr中，这意味着直接修改这个对象，就能够影响game.playerArr数组，而无需使用map方法。
            let theConnectionPlayer: Player | null = null
            // 当前这个连接的这个法官对象。这个对象就是game.judge属性，这意味着直接修改这个对象的属性（注意，不是说直接给这个对象赋新值），就能够影响game.judge属性。
            let theConnectionJudge: Judge | null = null

            if (socket.handshake.auth.type == '玩家') {
                theConnectionPlayer = this.playerConnection(socket)
            } else if (socket.handshake.auth.type == '法官'){
                 
            }

            console.log('进了')

            socket.on('玩家坐下', (n:number) => {
                console.log('玩家坐下')
                theConnectionPlayer!.sitDown(n)
                // 向所有用户广播当前座位信息。发送当前的脱敏信息即可。
                this.io.emit('座位信息广播', this.getNonSecretPlayerData())
            })
            socket.on('玩家起身', () => {
                theConnectionPlayer!.standUp()
                 // 向所有用户广播当前座位信息。发送当前的脱敏信息即可。
                 this.io.emit('座位信息广播', this.getNonSecretPlayerData())
            })
            // this.io.on('玩家起身', this.xx(socket, theConnectionPlayer))
            // this.io.on('游戏开始', this.tt(socket, theConnectionPlayer))
            // this.io.on('玩家坐下', this.zz(socket, theConnectionPlayer))
            // this.io.on('发起投票', this.qq(socket, theConnectionPlayer))
            // this.io.on('结束投票', this.qq(socket, theConnectionPlayer))
            // this.io.on('玩家投票了', this.qq(socket, theConnectionPlayer))
            // this.io.on('出局', this.qq(socket, theConnectionPlayer))
            // this.io.on('disconnect', this.qq(socket, theConnectionPlayer))
        })
    }
    playerConnection(socket): Player {
        // 用户连接时，需要提供token、type
        let connection_user_token = socket.handshake.auth.token
        let connection_user_type = socket.handshake.auth.type
        let connection_user_socketID = socket.id

        // 玩家在游戏过程中可能会退出浏览器，所以当他再次连接时，并不一定是在游戏开始时，此时应该为这个用户对齐数据。
        // 数据是脱敏的（在发给前端数据中，不会将其他用户的角色发给前端）
        socket.emit('玩家连接时信息对齐', {
            gameNumber: this.gameNumber,
            gameState: this.gameState,
            voteArr: this.voteArr,
            playerArr: this.getNonSecretPlayerData()
        })

        // 将用户加入数组。函数会返回这个用户实例
        return (this.addPlayer({
            token: connection_user_token,
            type: connection_user_type,
            socketID: connection_user_socketID
        }))
       
    }

    // 添加玩家
    addPlayer({ token, socketID, type }): Player {
        // 函数返回用户对象(Player类的实例），方便app.js直接使用这个用户对象
        let thePlayer;
        // 用户每次连接，都会产生一个全新的socketID。所以，要先遍历playerArr数组，看是否新加入的这个用户已经在数组中了。如果他已经在数组中了，则更新他的socketID和gameNumber和type；反之，就new一个新的User，并push进数组。
        if (this.playerArr.some(item => item.token == token)) {
            // 得到这项，并修改这项的socketID。
            // 这里无需使用map方法修改数组，而是利用引用类型值的特点，直接修改这个对象的属性即可。
            thePlayer = this.playerArr.filter(item => item.token == token)[0];
            thePlayer.socketID = socketID;
            thePlayer.gameNumber = this.gameNumber;
        } else {
            thePlayer = new Player({
                token,
                socketID,
                gameNumber: this.gameNumber
            });
            this.playerArr.push(thePlayer);
        }
        // console.log(thePlayer)
        // 返回User类的实例
        return thePlayer;
    }
    // 添加法官
    addJudge({ token, socketID, gameNumber }): Judge {
        return new Judge({
            token, 
            socketID,
            gameNumber
        })
    }
    // 得到非敏感玩家数组数据
    getNonSecretPlayerData() {
        return this.playerArr.map((item) => ({
            seat: item.seat,
            alive: item.alive,
            token: item.token
        }))
    }

}
